// Copyright (c) 2010 Manuel Peinado Gallego <manuel.peinado@gmail.com>
// Distributed under the MIT license


// SelectionManager.cpp : implementation of the SelectionManager class
//

#include "stdafx.h"
#include "WorldBuilder.h"
#include "SelectionManager.h"
#include "LogManager.h"
#include "Sphere.h"
#include "Ray.h"
#include "GeometryNode.h"
#include "Selectable.h"
#include <cfloat>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


SelectionManager::SelectionManager(Ui* ui)
:   WorldFollower(WorldFollower::IsNodeListener),
    m_subSelection(-1), 
    m_selection(NULL), m_ui(ui)
{
}

SelectionManager::~SelectionManager()
{
    // Check that all listeners have removed themselves
    ASSERT(m_changeListeners.empty());
}

// -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -

void SelectionManager::addSelectionChangeListener(
    SelectionChangeListener* listener)
{
    ASSERT(m_changeListeners.find(listener) == m_changeListeners.end());
    m_changeListeners.insert(listener);

    // Send first notification
    listener->onSelectionChanged(this);
}

void SelectionManager::removeSelectionChangeListener(
    SelectionChangeListener * listener)
{
    ASSERT(m_changeListeners.find(listener) != m_changeListeners.end());
    m_changeListeners.erase(listener);
}

void SelectionManager::notifyChangeListeners()
{
    typedef std::set<SelectionChangeListener*>::iterator It;
    for(It it = m_changeListeners.begin(); it != m_changeListeners.end(); ++it)
    {
        (*it)->onSelectionChanged(this);
    }
}

// -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -

bool SelectionManager::select(Selectable* item, int subSelection)
{
    bool changed = m_selection != item || subSelection != m_subSelection;
    
    // Don't do anything unless something has really changed
    if(changed)
    {
        // Don't change selection if any of the ready listeners doesn't want
        m_subSelection = subSelection;
        m_selection = item;
        
        m_ui->getLogManager().addLogMessage("Selection change");
        notifyChangeListeners();
    }
    return changed;
}

bool SelectionManager::clearSelection(bool forceNotification)
{
    bool changed = m_selection != NULL;
    
    if(changed || forceNotification)
    {
        // Don't change selection if any of the ready listeners doesn't want
        m_selection  = NULL;
        m_subSelection = -1;
        notifyChangeListeners();
    }
    return changed;
}

Selectable* SelectionManager::getSelection() const
{
    return m_selection;
}

int SelectionManager::getSubSelection()
{
    return m_subSelection;
}

// -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -

void SelectionManager::clearListeners()
{
    m_changeListeners.clear();
}

// -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -

void SelectionManager::onNodeEvent(const NodeEvent& event_)
{
    if(event_.type != NodeEvent::NodeRemoved)
    {
        return;
    }

    // Change the selection in case the removed node is selected, to avoid 
    // ending up with a pointer to an object that no longer exists
    if((Selectable*)event_.node == m_selection)
    {
        clearSelection();
    }
}
